In [1]:
import numpy as np
import matplotlib.pyplot as plt
import scipy.io.wavfile  as wavfile
import winsound
# plotting 3D complex plane
from mpl_toolkits.mplot3d import Axes3D
import os

Utils functions

In [246]:
def fnNormalizeFloatTo16Bit(yFloat):
    y_16bit = [int(s*32767) for s in yFloat]
    return(np.array(y_16bit, dtype='int16'))

# The input is a float array (should have dynamic value from -1.00 to +1.00
def fnNormalize16BitToFloat(y_16bit):
    yFloat = [float(s/32767.0) for s in y_16bit]
    return(np.array(yFloat, dtype='float'))

#checking answers:
def dump(x,y):
    for i in range(len(x)):
        print(f"{i}. {x[i]} -- {y[i]}")

Question 1

The equation to be plotted and sampled is $𝑦(t) = 0.1\cos(2\pi F t)$

In [8]:
def GenSampledSinusoid(A=1,Freq=1000,Phi=0, Fs=16000,sTime=-10,eTime=10):
    #This function returns a sinusoid given its charateristics 
    n = np.arange(sTime,eTime,1.0/Fs)                       #arange does not include end value 
    y = A*np.cos(2 * np.pi * Freq * n + Phi)
    return (n,y)
In [6]:
def stemplot(x,y,figsize=(10,10)):
    plt.figure(figsize=figsize)
    plt.stem(x,y,use_line_collection=True,basefmt="b")

Plotting this 1a

function is $y(t)=0.1\cos(2\pi F t)$ with $F_s$ = 16000Hz, F = 1000Hz

In [7]:
Fs_1a = 16000
F_1a = 1000
num_pts_to_plot=100  #for aesthetics 
sTime_1a=0
eTime_1a = sTime_1a+1.0/Fs_1a*num_pts_to_plot
(x_1a,y_1a) = GenSampledSinusoid(A=0.1,Fs=Fs_1a,Freq=F_1a,sTime=sTime_1a,eTime=eTime_1a)
stemplot(x_1a,y_1a,(20,10))
In [233]:
(messx,messy) = GenSampledSinusoid(A=0.5,Fs=16000,Freq=1000,Phi=np.pi/2,sTime=sTime_1a,eTime=eTime_1a)
stemplot(messx,messy,(20,10))
In [9]:
def playSoundFromWav(x,y,Fs = 16000,filename='t1_16bit.wav'):
    y_1a_16bit = fnNormalizeFloatTo16Bit(y)
    # Lets save the file, fname, sequence, and samplingrate needed
    wavfile.write(filename, Fs, y_1a_16bit)
    # Lets play the wavefile using winsound given the wavefile saved above
    #unfortunately winsound ONLY likes u16 bit values
    #thats why we had to normalize y->y_norm (16 bits) integers to play using winsounds
    winsound.PlaySound(filename, winsound.SND_FILENAME)
    #cleanup
    os.remove(filename)
In [12]:
(x_1a_long,y_1a_long) = GenSampledSinusoid(A=0.5,Fs=16000,Freq=1000,sTime=0,eTime=1.4)
#the one we did above is too short for a sound, we will make a longer one
playSoundFromWav(x_1a_long,y_1a_long)

Generate a bunch of files in steps defined

In [235]:
start_f=2000
stop_f=32000
step=2000
Amp = 1
Fs=16000
for f in range(start_f,stop_f+step,step):
    print(f"Playing sound for freq = {f}")
    (x,y) = GenSampledSinusoid(A=Amp,Fs=Fs,Freq=f,sTime=0,eTime=0.5)
    playSoundFromWav(x,y,Fs=Fs)
Playing sound for freq = 2000
Playing sound for freq = 4000
Playing sound for freq = 6000
Playing sound for freq = 8000
Playing sound for freq = 10000
Playing sound for freq = 12000
Playing sound for freq = 14000
Playing sound for freq = 16000
Playing sound for freq = 18000
Playing sound for freq = 20000
Playing sound for freq = 22000
Playing sound for freq = 24000
Playing sound for freq = 26000
Playing sound for freq = 28000
Playing sound for freq = 30000
Playing sound for freq = 32000

Explaining aliasing

We can see that each sound as an increasing pitch up to 8kHz, then decreasing pitch till 16kHz, then increase pitch to 24kHz, then decrease again at 32kHz. This is due to aliasing, where by the sample frequency of 16kHz is not sufficient for the given F (Fs $>=$ 2f)

As such starting at 8kHz onwards, due to insufficient sampling rate, the points sampled can be reconstructed into sinusoid of different frequencies (these sinusoids are hence called aliases -- due to the fact that they pass by the same set of points). The reconstruction algorithm will then pick the sinusoid with lowest frequency. As such we will hear the sound of decreasing pitch from 8kHz - 16kHz as the aliases mirror each other through 8kHz mark.

The same thing happen fro 16khz - 32khz, with 24khz being the mirror line

1b

We shall now generate a) y(t) b) y[nT] for 6 cycles

In [15]:
Fs_1b = 16000
f_1b=1000
num_cycles = 6
num_pts_to_plot=int(Fs_1b/f_1b*num_cycles)
sTime_1b=0
(x_1b,y_1b) = GenSampledSinusoid(A=1,Fs=Fs_1b,Freq=f_1b,sTime=sTime_1b,eTime=sTime_1b+1.0/Fs_1b*num_pts_to_plot)
plt.figure(figsize=(20,10))
plt.subplot(311)
plt.plot(x_1b,y_1b)
plt.subplot(312)
plt.stem(x_1b,y_1b,use_line_collection=True,basefmt="b")
plt.subplot(313)
plt.stem(np.arange(0,len(x_1b),1),y_1b,use_line_collection=True,basefmt="b")
Out[15]:
<StemContainer object of 3 artists>

i. Comment on the relationships between y(t), y[nT]. \ y(t) is continous signal in time whereas y[nT] is a sampled signal. Both functions are with respect to time, hence their x-axes are the same. \ ii. Comment on y[nT] vs y[n]. \ y[nT] is the sampled signal and y[n] is the discrete signal. Both functions are discrete and their x-axes are in time and number of samples respectively

iii. Periodic proof \ For a discrete signal to be periodic, there exist an integer K such that \ y[n] = y[n+K] -- it means after K number of samples, the signal will repeat itself \ \ We assume that the signal is periodic, aka there exist a K such that y[n] = y[n+K]\ \ By applying the formula $y[n]=0.1\cos(2\pi \frac{F}{F_s} n)$ to both sides: \ $0.1\cos(2\pi \frac{F}{F_s} n)=0.1\cos(2\pi \frac{F}{F_s} (n+K))$ \ $0.1\cos(2\pi \frac{F}{F_s} n)=0.1\cos(2\pi \frac{F}{F_s} n +2\pi \frac{F}{F_s} K)$ \ Now we know that cosine is periodic for every 2 $\pi$ so \ $\cos(n) = \cos(n + 2\pi) = \cos(n + 4\pi) = ... = \cos(n + m2\pi)$ where m is an integer\ \ As such, if $y[n]$ is periodic , that means $2\pi \frac{F}{F_s} K$ needs to be a multiple of 2$\pi$ \ aka $\frac{F}{F_s}K$ is an integer \ For our question, F = 1000, Fs = 16000, hence the minimum K that will satisfy that condition is K = 16. As such, the signal is periodic every 16 samples \ \ *It is also important to note that if $\frac{F}{F_s}$ is irrational, there will not be any integer K that will make $\frac{F}{F_s}K$ an integer. For such case, we can conclude that such discrete signal is aperiodic.

In [226]:
def plot_alias(F,Fs,n_cycles= 6):
    F_1biv = F
    num_pts_percycle = 32
    num_of_cycles = n_cycles
    Fs_1biv=Fs
    x_1biv = np.arange(0,num_of_cycles/F_1biv,1/F_1biv/num_pts_percycle)
    y_1biv = np.cos(2*np.pi*F_1biv*x_1biv)
    y_alias = np.zeros_like(y_1biv)
    my_color = ["k" for _ in y_alias]
    for i in range(len(x_1biv)):
        if i%int(num_pts_percycle*F_1biv/Fs_1biv) == 0:
            y_alias[i] = np.cos(2*np.pi*F_1biv*x_1biv[i])
            my_color[i] = "r"
    plt.figure(figsize=(20,3))
    plt.vlines(x_1biv,0,y_alias,color=my_color)
    plt.scatter(x_1biv,y_alias,color=my_color)
    plt.plot(x_1biv,y_1biv)
    recon_x = [x_1biv[i] for i in range(len(my_color)) if my_color[i] == "r"]
    recon_y = [y_1biv[i] for i in range(len(my_color)) if my_color[i] == "r"]
    plt.plot(recon_x,recon_y)
In [227]:
plot_alias(17000,16000)

We see that although the sinusoid has 6 cycles, each of period 1/17000s\ due to inadequate sampling, it will only sample after 1/16000s. \ From these sampled points, the reconstruction algorithm will pick a different alias curve that has lowest frequency \ which in this case we can see that the reconstructed curve will have a much lower frequency than the original\ See in the case below where I plot 18 cycles of the original sinusoid

In [228]:
plot_alias(17000,16000,18)

Only after 17 cycles does the samples signal reach back 1.0. \ Thus the reconstructed signal is likely to have a period of 1000Hz

In [232]:
#Similarly if we do it on 18000Hz sampling rate
plot_alias(17000,20000,18)
plot_alias(17000,19000,18)
plot_alias(17000,17000,18)
plot_alias(17000,15000,18)
plot_alias(17000,14000,18) 

1c

In [102]:
Fs_1c = 16000
f_1c=1000
num_cycles = 6
num_pts_to_plot=int(Fs_1c/f_1c*num_cycles)
sTime_1c=0
(x_1c,y_1c) = GenSampledSinusoid(A=1,Fs=Fs_1c,Freq=f_1c,sTime=sTime_1c,eTime=sTime_1c+1.0/Fs_1c*num_pts_to_plot)
plt.figure(figsize=(20,10))
plt.subplot(211)
plt.plot(x_1c,y_1c)
plt.subplot(212)
plt.stem(x_1c,y_1c,use_line_collection=True,basefmt="b")
Out[102]:
<StemContainer object of 3 artists>

Yep it's the same as it depends on F/Fs

2. DFMT

In [9]:
class DTMFGenerator:
    user_freq = [697.0, 770.0, 852.0, 941.0,1209.0, 1336.0, 1477.0, 1633.0]
    user_tones = {
            '1': (user_freq[0], user_freq[4]),
            '2': (user_freq[0], user_freq[5]),
            '3': (user_freq[0], user_freq[6]),
            'A': (user_freq[0], user_freq[7]),
            '4': (user_freq[1], user_freq[4]),
            '5': (user_freq[1], user_freq[5]),
            '6': (user_freq[1], user_freq[6]),
            'B': (user_freq[1], user_freq[7]),
            '7': (user_freq[2], user_freq[4]),
            '8': (user_freq[2], user_freq[5]),
            '9': (user_freq[2], user_freq[6]),
            'C': (user_freq[2], user_freq[7]),
            '*': (user_freq[3], user_freq[4]),
            '0': (user_freq[3], user_freq[5]),
            '#': (user_freq[3], user_freq[6]),
            'D': (user_freq[3], user_freq[7])
        }
    def genDTMF(key,Fs,dur,A=0.5,sTime=0,Phi=0):
        if key in DTMFGenerator.user_tones:
            (f1,f2) = DTMFGenerator.user_tones.get(key)
            t = np.arange(sTime,dur,1.0/Fs)
            yfloat = A*(np.cos(2*np.pi*f1*t+Phi)+np.cos(2*np.pi*f2*t+Phi))
            return (t,yfloat)
        else:
            print("Press a valid key le")
    def genDTMFseq(keyseq,Fs,durseq,A=0.5,sTime=0,Phi=0):
        assert len(keyseq) == len(durseq), "keyseq len is different from durseq"
        t = np.arange(sTime,sum(durseq),1.0/Fs)
        y = np.array([])
        for index, dur in enumerate(durseq):
            _,y_seg = DTMFGenerator.genDTMF(keyseq[index],Fs,dur)
            y = np.concatenate((y,y_seg),axis=None)
        return (t,y)
In [15]:
DTMFGen = DTMFGenerator()
(t_2,y_2) = DTMFGenerator.genDTMF('1',16000,1.0)
playSoundFromWav(t_2,y_2)
In [10]:
(t_2,y_2) = DTMFGenerator.genDTMFseq('123456789',16000,[0.1*(i+1) for i in range(9)])
playSoundFromWav(t_2,y_2)

Q3

In [243]:
A3 = 2
B3 = 0.5
Fs3= 180
num_cycles = 6
pts_per_cycle = 20
num_pts_to_plot= num_cycles*pts_per_cycle
sTime3=0


x_n_3,y1_3 = GenSampledSinusoid(A=A3,Freq=10,Phi=0, Fs=Fs3,sTime=sTime3,eTime=sTime3+1.0/Fs3*num_pts_to_plot)
_ , y2_3=GenSampledSinusoid(A=B3,Freq=15,Phi=0, Fs=Fs3,sTime=sTime3,eTime=sTime3+1.0/Fs3*num_pts_to_plot)

plt.figure(figsize=(20,10))
plt.subplot(311)
plt.stem(x_n_3,y1_3,use_line_collection=True,basefmt="b")
plt.subplot(312)
plt.stem(x_n_3,y2_3,use_line_collection=True,basefmt="b")
plt.subplot(313)
plt.stem(x_n_3,y1_3+y2_3,use_line_collection=True,basefmt="b")
Out[243]:
<StemContainer object of 3 artists>
In [247]:
dump(x_n_3,y1_3+y2_3)
0. 0.0 -- 2.5
1. 0.005555555555555556 -- 2.312397943464036
2. 0.011111111111111112 -- 1.782088886237956
3. 0.016666666666666666 -- 1.0000000000000004
4. 0.022222222222222223 -- 0.09729635533386094
5. 0.02777777777777778 -- -0.78030905722608
6. 0.03333333333333333 -- -1.4999999999999996
7. 0.03888888888888889 -- -1.9651015881301752
8. 0.044444444444444446 -- -2.129385241571817
9. 0.05 -- -2.0
10. 0.05555555555555556 -- -1.6293852415718169
11. 0.061111111111111116 -- -1.0990761843457368
12. 0.06666666666666667 -- -0.5000000000000009
13. 0.07222222222222223 -- 0.08571634655835864
14. 0.07777777777777778 -- 0.5972963553338602
15. 0.08333333333333334 -- 1.0000000000000004
16. 0.08888888888888889 -- 1.282088886237956
17. 0.09444444444444444 -- 1.4463725396795972
18. 0.1 -- 1.5
19. 0.10555555555555556 -- 1.4463725396795977
20. 0.11111111111111112 -- 1.2820888862379562
21. 0.11666666666666667 -- 1.0000000000000007
22. 0.12222222222222223 -- 0.5972963553338604
23. 0.1277777777777778 -- 0.08571634655835614
24. 0.13333333333333333 -- -0.49999999999999845
25. 0.1388888888888889 -- -1.099076184345737
26. 0.14444444444444446 -- -1.6293852415718169
27. 0.15 -- -1.999999999999999
28. 0.15555555555555556 -- -2.129385241571817
29. 0.16111111111111112 -- -1.9651015881301745
30. 0.16666666666666669 -- -1.4999999999999996
31. 0.17222222222222222 -- -0.7803090572260808
32. 0.17777777777777778 -- 0.09729635533385866
33. 0.18333333333333335 -- 1.0000000000000018
34. 0.18888888888888888 -- 1.782088886237953
35. 0.19444444444444445 -- 2.312397943464036
36. 0.2 -- 2.5
37. 0.20555555555555557 -- 2.3123979434640356
38. 0.2111111111111111 -- 1.7820888862379587
39. 0.21666666666666667 -- 1.000000000000001
40. 0.22222222222222224 -- 0.09729635533386122
41. 0.22777777777777777 -- -0.7803090572260776
42. 0.23333333333333334 -- -1.499999999999998
43. 0.2388888888888889 -- -1.9651015881301759
44. 0.24444444444444446 -- -2.1293852415718177
45. 0.25 -- -2.0000000000000013
46. 0.2555555555555556 -- -1.629385241571815
47. 0.2611111111111111 -- -1.0990761843457342
48. 0.26666666666666666 -- -0.5000000000000031
49. 0.27222222222222225 -- 0.08571634655836163
50. 0.2777777777777778 -- 0.5972963553338635
51. 0.2833333333333333 -- 1.0000000000000022
52. 0.2888888888888889 -- 1.2820888862379562
53. 0.29444444444444445 -- 1.4463725396795983
54. 0.3 -- 1.5
55. 0.3055555555555556 -- 1.4463725396795954
56. 0.3111111111111111 -- 1.2820888862379571
57. 0.31666666666666665 -- 1.0
58. 0.32222222222222224 -- 0.5972963553338584
59. 0.3277777777777778 -- 0.08571634655835608
60. 0.33333333333333337 -- -0.5000000000000007
61. 0.3388888888888889 -- -1.0990761843457362
62. 0.34444444444444444 -- -1.6293852415718153
63. 0.35000000000000003 -- -2.0000000000000004
64. 0.35555555555555557 -- -2.129385241571816
65. 0.3611111111111111 -- -1.9651015881301757
66. 0.3666666666666667 -- -1.4999999999999973
67. 0.37222222222222223 -- -0.7803090572260785
68. 0.37777777777777777 -- 0.09729635533385234
69. 0.38333333333333336 -- 0.9999999999999989
70. 0.3888888888888889 -- 1.7820888862379558
71. 0.3944444444444445 -- 2.3123979434640387
72. 0.4 -- 2.5
73. 0.40555555555555556 -- 2.3123979434640383
74. 0.41111111111111115 -- 1.782088886237955
75. 0.4166666666666667 -- 0.9999999999999976
76. 0.4222222222222222 -- 0.09729635533386752
77. 0.4277777777777778 -- -0.7803090572260808
78. 0.43333333333333335 -- -1.5000000000000002
79. 0.4388888888888889 -- -1.9651015881301757
80. 0.4444444444444445 -- -2.129385241571816
81. 0.45 -- -2.0000000000000018
82. 0.45555555555555555 -- -1.629385241571821
83. 0.46111111111111114 -- -1.099076184345736
84. 0.4666666666666667 -- -0.500000000000004
85. 0.47222222222222227 -- 0.08571634655835991
86. 0.4777777777777778 -- 0.5972963553338628
87. 0.48333333333333334 -- 1.0000000000000036
88. 0.48888888888888893 -- 1.2820888862379574
89. 0.49444444444444446 -- 1.4463725396795972
90. 0.5 -- 1.5
91. 0.5055555555555555 -- 1.4463725396795963
92. 0.5111111111111112 -- 1.2820888862379498
93. 0.5166666666666667 -- 0.99999999999999
94. 0.5222222222222223 -- 0.597296355333852
95. 0.5277777777777778 -- 0.0857163465583638
96. 0.5333333333333333 -- -0.49999999999999367
97. 0.5388888888888889 -- -1.09907618434573
98. 0.5444444444444445 -- -1.6293852415718173
99. 0.55 -- -1.9999999999999998
100. 0.5555555555555556 -- -2.1293852415718137
101. 0.5611111111111111 -- -1.9651015881301714
102. 0.5666666666666667 -- -1.4999999999999982
103. 0.5722222222222223 -- -0.7803090572260778
104. 0.5777777777777778 -- 0.0972963553338611
105. 0.5833333333333334 -- 0.9999999999999976
106. 0.5888888888888889 -- 1.7820888862379516
107. 0.5944444444444444 -- 2.312397943464034
108. 0.6 -- 2.5
109. 0.6055555555555556 -- 2.3123979434640325
110. 0.6111111111111112 -- 1.7820888862379514
111. 0.6166666666666667 -- 1.0000000000000049
112. 0.6222222222222222 -- 0.09729635533386885
113. 0.6277777777777778 -- -0.7803090572260709
114. 0.6333333333333333 -- -1.4999999999999933
115. 0.638888888888889 -- -1.9651015881301797
116. 0.6444444444444445 -- -2.1293852415718186
117. 0.65 -- -2.000000000000002
118. 0.6555555555555556 -- -1.6293852415718193
119. 0.6611111111111111 -- -1.099076184345746
120. 0.6666666666666667 -- -0.49999999999999867
$$f3=gcd(f1,f2)$$

d. \ It is a periodic signal so it's a power signal (infinite energy) \ for the period of $f_{3}$, $T_{3}$ of 0.2s = 2 $T_{1}$ = $3 T_{2}$ \ Power of $f_{1}, P_{1}$ is $A^2/2$ \ Power of $f_{2}, P_{2}$ is $B^2/2$ \ Power of $f_{3}$ is

$ P_{3}= 1/T * \lim_{T\rightarrow \infty} {1 \over {T}} \int_{0}^T |A\cos(2\pi 10 t)+B\cos(2\pi 15 t)|^2 dt \\ = 1/T * \lim_{T\rightarrow \infty} {1 \over {T}} \int_{0}^T [ A^2\cos^2(2\pi 10 t)+B^2\cos^2(2\pi 15 t) +2AB\cos(2\pi 10 t)\cos(2\pi 15 t)]dt \\ = 1/T * \lim_{T\rightarrow \infty} {1 \over {T}} \int_{0}^T [ A^2 *\frac{1 + \cos(2\pi 20 t)}{2} + B^2 *\frac{1 + \cos(2\pi 30 t)}{2}+ ] dt \\ = 1/T * [ A^2 *(\frac{1}{2}|_{0}^T+ sumsinusoid|_{0}^T ) + B^2 *(\frac{1}{2}|_{0}^{T} + sumsinusoid|_{0}^T) +2AB*sumsinusoid|_{0}^T ] = \frac{A^2}{2} + \frac{B^2}{2} $

we can prove that the $2AB*\frac{\cos(2\pi25t) + \cos(2\pi5 t)}{2}$ will always integrate to 0 because:\ the combined frequency $f_0 = gcd(f_1,f_2)$ -> period $T_0 = 1/gcd(f_1,f_2) $\ by math, $gcd(f_1,f_2) = gcd(f_1+f_2,f_2) = gcd(f_1-f2,f_2)$ aka the $2AB*\frac{\cos(2\pi25t) + \cos(2\pi5 t)}{2}$ will have complete cycles within T0

Q.4

In [18]:
Amp_4 = 0.95
somega_4 = 2*np.pi/36
phi_4=0

numSamples = 200
n_4 = np.arange(0, numSamples, 1)
y_4= np.multiply(np.power(Amp_4, n_4), np.exp(1j * somega_4 * n_4+phi_4))
In [175]:
### Packed version 
def qn_4(Amp_4 = 0.95,somega_4 = 2*np.pi/36, phi_4=0,    numSamples = 200):

    n_4 = np.arange(0, numSamples, 1)
    y_4= np.multiply(np.power(Amp_4, n_4), np.exp(1j * somega_4 * n_4+phi_4))
    
    fig = plt.figure(1,figsize=(45,15))
    plt.rcParams['legend.fontsize'] = 10
    plt.subplot(131)
    plt.plot(n_4[0:numSamples], y_4[0:numSamples].real,'y--o')
    plt.plot(n_4[0:numSamples], y_4[0:numSamples].imag,'k--o')
    plt.xlabel('sample index n'); plt.ylabel('y[n]')
    plt.title('Complex exponential (red=real) (green=imag)')
    plt.grid()
    
    plt.subplot(132,projection='polar')
    for y in y_4:
        plt.polar([0,np.angle(y)],[0,np.abs(y)],marker='o')

    plt.title('Polar plot showing phasors at n=0..N')

    ax = fig.add_subplot(1, 3, 3, projection='3d')
    scaling_factor = 1
    scaling = np.array([np.power(scaling_factor,int(i)) for i in range(len(n_4))])
    scaled_y4 = scaling*y_4
    reVal = scaled_y4[0:numSamples].real
    imgVal = scaled_y4[0:numSamples].imag
    ax.plot(n_4,reVal, imgVal,  label='complex exponential phasor')
    ax.scatter(n_4,reVal,imgVal, c='k', marker='o')
    ax.set_xlabel('sample n')
    ax.set_ylabel('real')
    ax.set_zlabel('imag')
    ax.legend()
    plt.show()
In [174]:
qn_4()
qn_4(somega_4=2*np.pi/18)

Q5

In [172]:
def qn_5(Amp_5 = 1,N_5 = 16,k_5 = 1,phi_5=0,numSamples_5 = 16):
    n_5 = np.arange(0, numSamples_5, 1)
    y_5= np.multiply(np.power(Amp_5, n_5), np.exp(1j * 2*np.pi/N_5*k_5* n_5+phi_5))
    fig = plt.figure(1,figsize=(50,15))
    plt.rcParams['legend.fontsize'] = 10
    plt.subplot(131)
    plt.plot(n_5[0:numSamples_5], y_5[0:numSamples_5].real,'y--o')
    plt.plot(n_5[0:numSamples_5], y_5[0:numSamples_5].imag,'k--o')
    plt.xlabel('sample index n'); plt.ylabel('y[n]')
    plt.title('Complex exponential (red=real) (green=imag)')
    plt.grid()

    plt.subplot(132,projection='polar')
    for y in y_5:
        plt.polar([0,np.angle(y)],[0,np.abs(y)],marker='o')

    plt.title('Polar plot showing phasors at n=0..N')

    ax = fig.add_subplot(1, 3, 3, projection='3d')
    scaling_factor = 1
    scaling = np.array([np.power(scaling_factor,int(i)) for i in range(len(n_5))])
    scaled_y5 = scaling*y_5
    reVal = scaled_y5[0:numSamples_5].real
    imgVal = scaled_y5[0:numSamples_5].imag
    ax.plot(n_5,reVal, imgVal,  label='complex exponential phasor')
    ax.scatter(n_5,reVal,imgVal, c='k', marker='o')
    ax.set_xlabel('sample n')
    ax.set_ylabel('real')
    ax.set_zlabel('imag')
    ax.legend()
    plt.show()
#qn_5(k_5=0,numSamples_5=32)
qn_5(k_5=3,numSamples_5=32)
In [176]:
for k in range(4):
    qn_5(k_5=k, numSamples_5=16)

We can see that $$\frac{2\pi}{N} k n = \omega n$$ There are a few observation:

  • N is number of samples
  • k is the number of cycles of it completes after N samples
  • 2 pi k/N is the angular displacement per sample
  • if k and N are integers then signal is periodic
  • As u increase k/N (by increasing k and keep N constant at 16), we can see that the digital angular frequency increases and the sampled signal makes more radian per seconds (in 3D plot). As angular frequency increases it will also complete more number of cycles